package org.batatasframework.support.database.jdbc;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;

import javax.sql.DataSource;

import org.batatasframework.support.database.spi.ResultReadable;
import org.batatasframework.support.database.sql.QueryParameter;


public class ConnectionAccessor implements AutoCloseable{
	
	private Connection connection;
	private Statement statement;
	private boolean isTransaction = false;
	
	public static ConnectionAccessor get(Connection connection){
		return new ConnectionAccessor(connection);
	}
	
	public static ConnectionAccessor get(DataSource dataSource) throws SQLException{
		return new ConnectionAccessor(dataSource.getConnection());
	}
	
	public static ConnectionAccessor beginTransaction(DataSource dataSource) throws SQLException{
		return get(dataSource).beginTransaction();
	}
	
	public ConnectionAccessor(Connection connection){
		this.connection = connection;
	}
	
	protected Statement getStatement() throws SQLException{
		if(null == statement || statement.isClosed()){
			statement = null;
			statement = connection.createStatement();
		}
		return statement;
	}
	
	public ConnectionAccessor beginTransaction() throws SQLException{
		isTransaction = true;
		connection.setAutoCommit(false);
		
		return this;
	}
	
	public void commit() throws SQLException{
		connection.commit();
	}
	
	public void error(Exception exception) throws Exception{
		if(isTransaction){
			/*
			 * 当数据库操作的过程中发生异常，则应该catch并调用这个方法进行异常的设置；
			 * 如果当前使用事务，则在这里需要回滚
			 */
			connection.rollback();
		}
		throw exception;
	}
	
	@Override
	public void close() throws Exception {
		if(null != statement){
			statement.close();
		}
		
		if(isTransaction){
			connection.setAutoCommit(true);
		}
		connection.close();
		
		//释放内存
		connection = null;
		isTransaction = false;
	}

	public DatabaseMetaData getMetaData() throws SQLException {
		return connection.getMetaData();
	}

	public PreparedStatement prepareStatement(String sql) throws SQLException {
		return connection.prepareStatement(sql);
	}

	public Statement createStatement() throws SQLException {
		return connection.createStatement();
	}
	
	public ResultSet executeQuery(String sql) throws SQLException{
		return getStatement().executeQuery(sql);
	}
	
	public void executeQuery(String sql, List<QueryParameter> paramenters, ResultReadable reader) throws Exception{
		if(paramenters.isEmpty()){
			executeQuery(sql, reader);
		}else{
			try(PreparedStatement ps = prepareStatement(sql)){
				for(QueryParameter qp : paramenters){
					qp.set(ps);
				}
				reader.read(ps.executeQuery());
			}
		}
	}
	
	public void executeQuery(String sql, ResultReadable reader) throws Exception{
		try(Statement statement = createStatement()){
			reader.read(statement.executeQuery(sql));
		}
	}
	
	public void execute(String sql) throws Exception{
		try(Statement statement = createStatement()){
			statement.execute(sql);
		}
	}
	
	public void execute(String sql, List<QueryParameter> paramenters) throws Exception{
		if(paramenters.isEmpty()){
			execute(sql);
		}else{
			try(PreparedStatement ps = prepareStatement(sql)){
				for(QueryParameter qp : paramenters){
					qp.set(ps);
				}
				ps.execute();
			}
		}
	}

	public void rollback() throws SQLException {
		connection.rollback();
	}
}
